/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */

#include "at32f413.h"
#include "usbd_core.h"
#include "cdc_msc_class.h"
#include "cdc_msc_desc.h"
#include "usbd_int.h"
#include <rtthread.h>

#define DBG_TAG "usb"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

/** @addtogroup AT32F413_periph_examples
 * @{
 */

/** @addtogroup 413_USB_device_composite_vcp_msc USB_device_composite_vcp_msc
 * @{
 */

usbd_core_type usb_core_dev;
uint8_t usb_buffer[256];

/**
 * @brief  usb 48M clock select
 * @param  clk_s:USB_CLK_HICK, USB_CLK_HEXT
 * @retval none
 */
void usb_clock48m_select(usb_clk48_s clk_s)
{
    if (clk_s == USB_CLK_HICK)
    {
        crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_HICK);

        /* enable the acc calibration ready interrupt */
        crm_periph_clock_enable(CRM_ACC_PERIPH_CLOCK, TRUE);

        /* update the c1\c2\c3 value */
        acc_write_c1(7980);
        acc_write_c2(8000);
        acc_write_c3(8020);

        /* open acc calibration */
        acc_calibration_mode_enable(ACC_CAL_HICKTRIM, TRUE);
    }
    else
    {

        switch (system_core_clock)
        {
        /* 48MHz */
        case 48000000:
            crm_usb_clock_div_set(CRM_USB_DIV_1);
            break;

        /* 72MHz */
        case 72000000:
            crm_usb_clock_div_set(CRM_USB_DIV_1_5);
            break;

        /* 96MHz */
        case 96000000:
            crm_usb_clock_div_set(CRM_USB_DIV_2);
            break;

        /* 120MHz */
        case 120000000:
            crm_usb_clock_div_set(CRM_USB_DIV_2_5);
            break;

        /* 144MHz */
        case 144000000:
            crm_usb_clock_div_set(CRM_USB_DIV_3);
            break;

        /* 168MHz */
        case 168000000:
            crm_usb_clock_div_set(CRM_USB_DIV_3_5);
            break;

        /* 192MHz */
        case 192000000:
            crm_usb_clock_div_set(CRM_USB_DIV_4);
            // LOG_D("CRM_USB_DIV_4");
            break;
        /* 200MHz */
        case 200000000:
            crm_usb_clock_div_set(CRM_USB_DIV_4);
            break;

        default:
            break;
        }
        // LOG_D("system_core_clock: %d", system_core_clock);
    }
}

/**
 * @brief  main function.
 * @param  none
 * @retval none
 */
int usb_main_init(void)
{
    // uint16_t data_len;

    // uint32_t timeout;

    // uint8_t send_zero_packet = 0;

    /* config nvic priority group */
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);


    // system_clock_config();
    // at32_board_init();

    /* select usb 48m clcok source */
    usb_clock48m_select(USB_CLK_HEXT);

    /* enable usb clock */
    crm_periph_clock_enable(CRM_USB_PERIPH_CLOCK, TRUE);

    /* enable usb interrupt */
    nvic_irq_enable(USBFS_L_CAN1_RX0_IRQn, 0, 0);

    /* usb core init */
    usbd_core_init(&usb_core_dev, USB, &cdc_msc_class_handler, &cdc_msc_desc_handler, 0);

    /* enable usb pull-up */
    usbd_connect(&usb_core_dev);

    // while (1)
    // {
    //     /* get usb vcp receive data */
    //     data_len = usb_vcp_get_rxdata(&usb_core_dev, usb_buffer);

    //     if (data_len > 0 || send_zero_packet == 1)
    //     {
    //         /* bulk transfer is complete when the endpoint does one of the following
    //            1 has transferred exactly the amount of data expected
    //            2 transfers a packet with a payload size less than wMaxPacketSize or transfers a zero-length packet
    //         */
    //         if (data_len > 0)
    //             send_zero_packet = 1;

    //         if (data_len == 0)
    //             send_zero_packet = 0;

    //         timeout = 5000000;
    //         do
    //         {
    //             /* send data to host */
    //             if (usb_vcp_send_data(&usb_core_dev, usb_buffer, data_len) == SUCCESS)
    //             {
    //                 break;
    //             }
    //         } while (timeout--);
    //     }
    // }
    return 0;
}

/**
 * @brief  this function handles usb interrupt.
 * @param  none
 * @retval none
 */
void USBFS_L_CAN1_RX0_IRQHandler(void)
{
    usbd_irq_handler(&usb_core_dev);
}
uint16_t vcp_get_rxdata(uint8_t *p_buf)
{
    return usb_vcp_get_rxdata(&usb_core_dev, p_buf);
}
void vcp_send_data(uint8_t *p_buf, uint16_t len)
{
    usb_vcp_send_data(&usb_core_dev, p_buf, len);
}
/**
 * @brief  usb delay millisecond function.
 * @param  ms: number of millisecond delay
 * @retval none
 */
void usb_delay_ms(uint32_t ms)
{
    /* user can define self delay function */
    rt_thread_delay(ms);
}

/**
 * @brief  usb delay microsecond function.
 * @param  us: number of microsecond delay
 * @retval none
 */
// void usb_delay_us(uint32_t us)
// {
//     delay_us(us);
// }
/**
 * @}
 */

/**
 * @}
 */
